/// ------------------------------------------------------------------------------------------------------------------------------------
///
/// MIT License
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
/// SOFTWARE.
///
/// Copyright (c) 2023 ycz. All rights reserved.
///
/// Created by ycz on 2023/12/22.
///
/// @file  y_nvs.c
///
/// @brief
///     y_nvs 是一种嵌入式设备的非易失性存储库,常用于保存系统参数
///
/// ------------------------------------------------------------------------------------------------------------------------------------



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 头文件
/// ------------------------------------------------------------------------------------------------------------------------------------

#include "y_nvs.h"

#include <string.h>
#include "y_sa.h"



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 宏定义
/// ------------------------------------------------------------------------------------------------------------------------------------

#define NVS_ADDR Y_LL_NVS_ADDR  ///< NVS 表开始地址
#define NVS_SIZE Y_LL_NVS_SIZE  ///< NVS 大小 只有 2048 4096 8192 16384 四种选择



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 结构体
/// ------------------------------------------------------------------------------------------------------------------------------------

#pragma pack(1)  // 设置结构体 1 字节对齐

/// NVS 结构体
typedef struct {
#if (NVS_SIZE == 2048)

    struct {
        struct {
            uint8_t key[24];   ///< key
            uint8_t data[64];  ///< value
            uint8_t size;      ///< 大小
            bool    is_reset;  ///< 是否允许重置
            uint8_t sum8;      ///< sum8
        } arr_64[6];
        struct {
            uint8_t key[24];    ///< key
            uint8_t data[128];  ///< value
            uint8_t size;       ///< 大小
            bool    is_reset;   ///< 是否允许重置
            uint8_t sum8;       ///< sum8
        } arr_128[1];
        struct {
            uint8_t key[24];    ///< key
            uint8_t size;       ///< value
            uint8_t data[255];  ///< 大小
            bool    is_reset;   ///< 是否允许重置
            uint8_t sum8;       ///< sum8
        } arr_256[1];
        struct {
            uint8_t  key[24];   ///< key
            uint8_t  data[11];  ///< value
            uint16_t size;      ///< 大小
            bool     is_reset;  ///< 是否允许重置
            uint8_t  sum8;      ///< sum8
        } arr_big[1];           ///< 占位保留 凑够字节
        uint16_t crc16;         ///< nvs 表校验值
    } table[2];                 ///< 主分区和备份分区

#elif (NVS_SIZE == 4096)

    struct {
        struct {
            uint8_t key[24];   ///< key
            uint8_t data[64];  ///< value
            uint8_t size;      ///< 大小
            bool    is_reset;  ///< 是否允许重置
            uint8_t sum8;      ///< sum8
        } arr_64[8];
        struct {
            uint8_t key[24];    ///< key
            uint8_t data[128];  ///< value
            uint8_t size;       ///< 大小
            bool    is_reset;   ///< 是否允许重置
            uint8_t sum8;       ///< sum8
        } arr_128[2];
        struct {
            uint8_t key[24];    ///< key
            uint8_t size;       ///< value
            uint8_t data[255];  ///< 大小
            bool    is_reset;   ///< 是否允许重置
            uint8_t sum8;       ///< sum8
        } arr_256[1];
        struct {
            uint8_t  key[24];    ///< key
            uint8_t  data[698];  ///< value
            uint16_t size;       ///< 大小
            bool     is_reset;   ///< 是否允许重置
            uint8_t  sum8;       ///< sum8
        } arr_big[1];            ///< 占位保留 凑够字节
        uint16_t crc16;          ///< nvs 表校验值
    } table[2];                  ///< 主分区和备份分区

#elif (NVS_SIZE == 8192)

    struct {
        struct {
            uint8_t key[24];   ///< key
            uint8_t data[64];  ///< value
            uint8_t size;      ///< 大小
            bool    is_reset;  ///< 是否允许重置
            uint8_t sum8;      ///< sum8
        } arr_64[11];
        struct {
            uint8_t key[24];    ///< key
            uint8_t data[128];  ///< value
            uint8_t size;       ///< 大小
            bool    is_reset;   ///< 是否允许重置
            uint8_t sum8;       ///< sum8
        } arr_128[2];
        struct {
            uint8_t key[24];    ///< key
            uint8_t size;       ///< value
            uint8_t data[255];  ///< 大小
            bool    is_reset;   ///< 是否允许重置
            uint8_t sum8;       ///< sum8
        } arr_256[1];
        struct {
            uint8_t  key[24];     ///< key
            uint8_t  data[2473];  ///< value
            uint16_t size;        ///< 大小
            bool     is_reset;    ///< 是否允许重置
            uint8_t  sum8;        ///< sum8
        } arr_big[1];             ///< 占位保留 凑够字节
        uint16_t crc16;           ///< nvs 表校验值
    } table[2];                   ///< 主分区和备份分区

#elif (NVS_SIZE == 16384)

    struct {
        struct {
            uint8_t key[24];   ///< key
            uint8_t data[64];  ///< value
            uint8_t size;      ///< 大小
            bool    is_reset;  ///< 是否允许重置
            uint8_t sum8;      ///< sum8
        } arr_64[22];
        struct {
            uint8_t key[24];    ///< key
            uint8_t data[128];  ///< value
            uint8_t size;       ///< 大小
            bool    is_reset;   ///< 是否允许重置
            uint8_t sum8;       ///< sum8
        } arr_128[6];
        struct {
            uint8_t key[24];    ///< key
            uint8_t size;       ///< value
            uint8_t data[255];  ///< 大小
            bool    is_reset;   ///< 是否允许重置
            uint8_t sum8;       ///< sum8
        } arr_256[4];
        struct {
            uint8_t  key[24];     ///< key
            uint8_t  data[4102];  ///< value
            uint16_t size;        ///< 大小
            bool     is_reset;    ///< 是否允许重置
            uint8_t  sum8;        ///< sum8
        } arr_big[1];             ///< 占位保留 凑够字节
        uint16_t crc16;           ///< nvs 表校验值
    } table[2];                   ///< 主分区和备份分区

#endif
} NVS_st;

#pragma pack()  // 恢复结构体默认对其方式



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 全局变量
/// ------------------------------------------------------------------------------------------------------------------------------------

static NVS_st g_nvs;  ///< nvs 表



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 公有函数
/// ------------------------------------------------------------------------------------------------------------------------------------

/// @brief   打印 y_nvs 版本信息
void y_nvs_print_version() {
    YLOG_VERSION("y_nvs", Y_NVS_MAJOR, Y_NVS_MINOR, Y_NVS_PATCH);
}

/// @brief   打印已保存的信息
void y_nvs_print() {
    uint16_t nvs_num = 0;
    for (int i = 0; i < sizeof(g_nvs.table[0].arr_64) / sizeof(g_nvs.table[0].arr_64[0]); ++i) {
        if (g_nvs.table[0].arr_64[i].size) {
            YLOGI("NVS  arr_64[%d]                    : %-24s %-3d", i, g_nvs.table[0].arr_64[i].key, g_nvs.table[0].arr_64[i].size);
            nvs_num++;
        }
    }
    for (int i = 0; i < sizeof(g_nvs.table[0].arr_128) / sizeof(g_nvs.table[0].arr_128[0]); ++i) {
        if (g_nvs.table[0].arr_128[i].size) {
            YLOGI("NVS  arr_128[%d]                   : %-24s %-3d", i, g_nvs.table[0].arr_128[i].key, g_nvs.table[0].arr_128[i].size);
            nvs_num++;
        }
    }
    for (int i = 0; i < sizeof(g_nvs.table[0].arr_256) / sizeof(g_nvs.table[0].arr_256[0]); ++i) {
        if (g_nvs.table[0].arr_256[i].size) {
            YLOGI("NVS  arr_256[%d]                   : %-24s %-3d", i, g_nvs.table[0].arr_256[i].key, g_nvs.table[0].arr_256[i].size);
            nvs_num++;
        }
    }
    for (int i = 0; i < sizeof(g_nvs.table[0].arr_big) / sizeof(g_nvs.table[0].arr_big[0]); ++i) {
        if (g_nvs.table[0].arr_big[i].size) {
            YLOGI("NVS  arr_big[%d]                   : %-24s %-3d", i, g_nvs.table[0].arr_big[i].key, g_nvs.table[0].arr_big[i].size);
            nvs_num++;
        }
    }
    YLOGI("NVS  table num                    : %d", nvs_num);
}

/// @brief   读取 k-v
/// @param   [in]  key                     键
/// @param   [out] value                   值
/// @param   [out] size                    值大小
/// @return  值大小
bool y_nvs_get(uint8_t *key, uint8_t *value, uint16_t *size) {

    // 断言
    YLOGA_FALSE(key);
    YLOGA_FALSE(value);
    YLOGA_FALSE(size);
    if (strlen((char *) key) > 24) {
        return false;
    }

    // 校验 crc16
    if (g_nvs.table[0].crc16 != y_utils_get_crc16((uint8_t *) &g_nvs.table[0], sizeof(NVS_st) / 2 - 2)) {
        // 主分区检验失败 校验备用分区 crc16
        if (g_nvs.table[1].crc16 != y_utils_get_crc16((uint8_t *) &g_nvs.table[1], sizeof(NVS_st) / 2 - 2)) {
            // 备用分区检验失败 重新从内存中读取一次
            y_ll_flash_read(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st));
            if (g_nvs.table[0].crc16 != y_utils_get_crc16((uint8_t *) &g_nvs.table[0], sizeof(NVS_st) / 2 - 2)) {
                if (g_nvs.table[1].crc16 != y_utils_get_crc16((uint8_t *) &g_nvs.table[1], sizeof(NVS_st) / 2 - 2)) {
                    YLOGE("nvs read error");
                    return false;
                }
                memcpy(&g_nvs.table[0], &g_nvs.table[1], sizeof(g_nvs.table[0]));  // 备用分区复制到主分区
            }
        } else {
            memcpy(&g_nvs.table[0], &g_nvs.table[1], sizeof(g_nvs.table[0]));  // 备用分区复制到主分区
        }
    }

    for (int i = 0; i < sizeof(g_nvs.table[0].arr_64) / sizeof(g_nvs.table[0].arr_64[0]); ++i) {
        if (strstr((char *) g_nvs.table[0].arr_64[i].key, (char *) key) && g_nvs.table[0].arr_64[i].size) {
            *size = g_nvs.table[0].arr_64[i].size;
            memcpy(value, g_nvs.table[0].arr_64[i].data, g_nvs.table[0].arr_64[i].size);
            return true;
        }
    }

    for (int i = 0; i < sizeof(g_nvs.table[0].arr_128) / sizeof(g_nvs.table[0].arr_128[0]); ++i) {
        if (strstr((char *) g_nvs.table[0].arr_128[i].key, (char *) key) && g_nvs.table[0].arr_128[i].size) {
            *size = g_nvs.table[0].arr_128[i].size;
            memcpy(value, g_nvs.table[0].arr_128[i].data, g_nvs.table[0].arr_128[i].size);
            return true;
        }
    }

    for (int i = 0; i < sizeof(g_nvs.table[0].arr_256) / sizeof(g_nvs.table[0].arr_256[0]); ++i) {
        if (strstr((char *) g_nvs.table[0].arr_256[i].key, (char *) key) && g_nvs.table[0].arr_256[i].size) {
            *size = g_nvs.table[0].arr_256[i].size;
            memcpy(value, g_nvs.table[0].arr_256[i].data, g_nvs.table[0].arr_256[i].size);
            return true;
        }
    }

    for (int i = 0; i < sizeof(g_nvs.table[0].arr_big) / sizeof(g_nvs.table[0].arr_big[0]); ++i) {
        if (strstr((char *) g_nvs.table[0].arr_big[i].key, (char *) key) && g_nvs.table[0].arr_big[i].size) {
            *size = g_nvs.table[0].arr_big[i].size;
            memcpy(value, g_nvs.table[0].arr_big[i].data, g_nvs.table[0].arr_big[i].size);
            return true;
        }
    }

    return false;
}

/// @brief   保存 k-v
/// @param   [in] key                      键
/// @param   [in] value                    值
/// @param   [in] size                     值大小
/// @param   [in] is_reset                 是否可以进行重置
/// @retval  true                          成功
/// @retval  false                         失败
bool y_nvs_set(uint8_t *key, uint8_t *value, uint16_t size, bool is_reset) {

    // 断言
    YLOGA_FALSE(key);
    YLOGA_FALSE(value);
    YLOGA_FALSE(size);
    if (strlen((char *) key) > 24) {
        return false;
    }

    // 先读取 判断有无改变 无改变则不操作内存
    if (size <= 256) {
        uint16_t tmp_size       = 0;
        uint8_t  tmp_value[256] = {0};
        if (y_nvs_get(key, tmp_value, &tmp_size) && tmp_size == size && memcmp(tmp_value, value, size) == 0) {
            return true;  // 要设置的内容未发生改变 不进行操作
        }
    } else {
        if (memcmp(g_nvs.table[0].arr_big[0].data, value, size) == 0) {
            return true;  // 要设置的内容未发生改变 不进行操作
        }
    }

    // 先删除已保存内容
    y_nvs_delete(key);

    if (size <= 64) {
        for (int i = 0; i < sizeof(g_nvs.table[0].arr_64) / sizeof(g_nvs.table[0].arr_64[0]); ++i) {
            if (g_nvs.table[0].arr_64[i].size == 0) {
                memcpy(g_nvs.table[0].arr_64[i].key, key, strlen((char *) key));
                memcpy(g_nvs.table[0].arr_64[i].data, value, size);
                g_nvs.table[0].arr_64[i].size     = size;
                g_nvs.table[0].arr_64[i].is_reset = is_reset;
                g_nvs.table[0].arr_64[i].sum8     = y_utils_get_sum8(g_nvs.table[0].arr_64[i].key, sizeof(g_nvs.table[0].arr_64[i]) - 1, true);
                g_nvs.table[0].crc16              = y_utils_get_crc16((uint8_t *) &g_nvs, sizeof(NVS_st) / 2 - 2);  // 更新 crc16
                memcpy(&g_nvs.table[1], &g_nvs.table[0], sizeof(g_nvs.table[0]));
                y_ll_flash_erase(NVS_ADDR, sizeof(NVS_st));
                return y_ll_flash_write(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st)) ? true : false;  // 保存数据到内存中
            }
        }
    }

    if (size <= 128) {
        for (int i = 0; i < sizeof(g_nvs.table[0].arr_128) / sizeof(g_nvs.table[0].arr_128[0]); ++i) {
            if (g_nvs.table[0].arr_128[i].size == 0) {
                memcpy(g_nvs.table[0].arr_128[i].key, key, strlen((char *) key));
                memcpy(g_nvs.table[0].arr_128[i].data, value, size);
                g_nvs.table[0].arr_128[i].size     = size;
                g_nvs.table[0].arr_128[i].is_reset = is_reset;
                g_nvs.table[0].arr_128[i].sum8     = y_utils_get_sum8(g_nvs.table[0].arr_128[i].key, sizeof(g_nvs.table[0].arr_128[i]) - 1, true);
                g_nvs.table[0].crc16               = y_utils_get_crc16((uint8_t *) &g_nvs, sizeof(NVS_st) / 2 - 2);  // 更新 crc16
                memcpy(&g_nvs.table[1], &g_nvs.table[0], sizeof(g_nvs.table[0]));
                y_ll_flash_erase(NVS_ADDR, sizeof(NVS_st));
                return y_ll_flash_write(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st)) ? true : false;  // 保存数据到内存中
            }
        }
    }

    if (size <= 256) {
        for (int i = 0; i < sizeof(g_nvs.table[0].arr_256) / sizeof(g_nvs.table[0].arr_256[0]); ++i) {
            if (g_nvs.table[0].arr_256[i].size == 0) {
                memcpy(g_nvs.table[0].arr_256[i].key, key, strlen((char *) key));
                memcpy(g_nvs.table[0].arr_256[i].data, value, size);
                g_nvs.table[0].arr_256[i].size     = size;
                g_nvs.table[0].arr_256[i].is_reset = is_reset;
                g_nvs.table[0].arr_256[i].sum8     = y_utils_get_sum8(g_nvs.table[0].arr_256[i].key, sizeof(g_nvs.table[0].arr_256[i]) - 1, true);
                g_nvs.table[0].crc16               = y_utils_get_crc16((uint8_t *) &g_nvs, sizeof(NVS_st) / 2 - 2);  // 更新 crc16
                memcpy(&g_nvs.table[1], &g_nvs.table[0], sizeof(g_nvs.table[0]));
                y_ll_flash_erase(NVS_ADDR, sizeof(NVS_st));
                return y_ll_flash_write(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st)) ? true : false;  // 保存数据到内存中
            }
        }
    }

    if (size <= sizeof(g_nvs.table[0].arr_big[0].data)) {
        for (int i = 0; i < sizeof(g_nvs.table[0].arr_big) / sizeof(g_nvs.table[0].arr_big[0]); ++i) {
            if (g_nvs.table[0].arr_big[i].size == 0) {
                memcpy(g_nvs.table[0].arr_big[i].key, key, strlen((char *) key));
                memcpy(g_nvs.table[0].arr_big[i].data, value, size);
                g_nvs.table[0].arr_big[i].size     = size;
                g_nvs.table[0].arr_big[i].is_reset = is_reset;
                g_nvs.table[0].arr_big[i].sum8     = y_utils_get_sum8(g_nvs.table[0].arr_big[i].key, sizeof(g_nvs.table[0].arr_big[i]) - 1, true);
                g_nvs.table[0].crc16               = y_utils_get_crc16((uint8_t *) &g_nvs, sizeof(NVS_st) / 2 - 2);  // 更新 crc16
                memcpy(&g_nvs.table[1], &g_nvs.table[0], sizeof(g_nvs.table[0]));
                y_ll_flash_erase(NVS_ADDR, sizeof(NVS_st));
                return y_ll_flash_write(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st)) ? true : false;  // 保存数据到内存中
            }
        }
    }

    YLOGE("no place to store");
    return false;  // 无处存放
}

/// @brief   删除 k-v
/// @param   [in] key                      键
/// @retval  true                          成功
/// @retval  false                         失败
bool y_nvs_delete(uint8_t *key) {

    // 断言
    YLOGA_FALSE(key);
    if (strlen((char *) key) > 24) {
        return false;
    }

    for (int i = 0; i < sizeof(g_nvs.table[0].arr_64) / sizeof(g_nvs.table[0].arr_64[0]); ++i) {
        if (strstr((char *) g_nvs.table[0].arr_64[i].key, (char *) key) && g_nvs.table[0].arr_64[i].size) {
            memset(&g_nvs.table[0].arr_64[i], 0, sizeof(g_nvs.table[0].arr_64[i]));
            g_nvs.table[0].crc16 = y_utils_get_crc16((uint8_t *) &g_nvs, sizeof(NVS_st) / 2 - 2);  // 更新 crc16
            memcpy(&g_nvs.table[1], &g_nvs.table[0], sizeof(g_nvs.table[0]));
            y_ll_flash_erase(NVS_ADDR, sizeof(NVS_st));
            return y_ll_flash_write(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st)) ? true : false;  // 保存数据到内存中
        }
    }

    for (int i = 0; i < sizeof(g_nvs.table[0].arr_128) / sizeof(g_nvs.table[0].arr_128[0]); ++i) {
        if (strstr((char *) g_nvs.table[0].arr_128[i].key, (char *) key) && g_nvs.table[0].arr_128[i].size) {
            memset(&g_nvs.table[0].arr_128[i], 0, sizeof(g_nvs.table[0].arr_128[i]));
            g_nvs.table[0].crc16 = y_utils_get_crc16((uint8_t *) &g_nvs, sizeof(NVS_st) / 2 - 2);  // 更新 crc16
            memcpy(&g_nvs.table[1], &g_nvs.table[0], sizeof(g_nvs.table[0]));
            y_ll_flash_erase(NVS_ADDR, sizeof(NVS_st));
            return y_ll_flash_write(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st)) ? true : false;  // 保存数据到内存中
        }
    }

    for (int i = 0; i < sizeof(g_nvs.table[0].arr_256) / sizeof(g_nvs.table[0].arr_256[0]); ++i) {
        if (strstr((char *) g_nvs.table[0].arr_256[i].key, (char *) key) && g_nvs.table[0].arr_256[i].size) {
            memset(&g_nvs.table[0].arr_256[i], 0, sizeof(g_nvs.table[0].arr_256[i]));
            g_nvs.table[0].crc16 = y_utils_get_crc16((uint8_t *) &g_nvs, sizeof(NVS_st) / 2 - 2);  // 更新 crc16
            memcpy(&g_nvs.table[1], &g_nvs.table[0], sizeof(g_nvs.table[0]));
            y_ll_flash_erase(NVS_ADDR, sizeof(NVS_st));
            return y_ll_flash_write(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st)) ? true : false;  // 保存数据到内存中
        }
    }

    for (int i = 0; i < sizeof(g_nvs.table[0].arr_big) / sizeof(g_nvs.table[0].arr_big[0]); ++i) {
        if (strstr((char *) g_nvs.table[0].arr_big[i].key, (char *) key) && g_nvs.table[0].arr_big[i].size) {
            memset(&g_nvs.table[0].arr_big[i], 0, sizeof(g_nvs.table[0].arr_big[i]));
            g_nvs.table[0].crc16 = y_utils_get_crc16((uint8_t *) &g_nvs, sizeof(NVS_st) / 2 - 2);  // 更新 crc16
            memcpy(&g_nvs.table[1], &g_nvs.table[0], sizeof(g_nvs.table[0]));
            y_ll_flash_erase(NVS_ADDR, sizeof(NVS_st));
            return y_ll_flash_write(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st)) ? true : false;  // 保存数据到内存中
        }
    }

    return false;
}

/// @brief   重置 nvs
/// @return
bool y_nvs_reset() {

    // 遍历删除需要重置的数据
    for (int i = 0; i < sizeof(g_nvs.table[0].arr_64) / sizeof(g_nvs.table[0].arr_64[0]); ++i) {
        if (g_nvs.table[0].arr_64[i].is_reset || g_nvs.table[0].arr_64[i].sum8 != y_utils_get_sum8(g_nvs.table[0].arr_64[i].key, sizeof(g_nvs.table[0].arr_64[i]) - 1, true)) {
            memset(&g_nvs.table[0].arr_64[i], 0, sizeof(g_nvs.table[0].arr_64[i]));
        }
    }
    for (int i = 0; i < sizeof(g_nvs.table[0].arr_128) / sizeof(g_nvs.table[0].arr_128[0]); ++i) {
        if (g_nvs.table[0].arr_128[i].is_reset || g_nvs.table[0].arr_128[i].sum8 != y_utils_get_sum8(g_nvs.table[0].arr_128[i].key, sizeof(g_nvs.table[0].arr_128[i]) - 1, true)) {
            memset(&g_nvs.table[0].arr_128[i], 0, sizeof(g_nvs.table[0].arr_128[i]));
        }
    }
    for (int i = 0; i < sizeof(g_nvs.table[0].arr_256) / sizeof(g_nvs.table[0].arr_256[0]); ++i) {
        if (g_nvs.table[0].arr_256[i].is_reset || g_nvs.table[0].arr_256[i].sum8 != y_utils_get_sum8(g_nvs.table[0].arr_256[i].key, sizeof(g_nvs.table[0].arr_256[i]) - 1, true)) {
            memset(&g_nvs.table[0].arr_256[i], 0, sizeof(g_nvs.table[0].arr_256[i]));
        }
    }
    for (int i = 0; i < sizeof(g_nvs.table[0].arr_big) / sizeof(g_nvs.table[0].arr_big[0]); ++i) {
        if (g_nvs.table[0].arr_big[i].is_reset || g_nvs.table[0].arr_big[i].sum8 != y_utils_get_sum8(g_nvs.table[0].arr_big[i].key, sizeof(g_nvs.table[0].arr_big[i]) - 1, true)) {
            memset(&g_nvs.table[0].arr_big[i], 0, sizeof(g_nvs.table[0].arr_big[i]));
        }
    }

    // 重新写入内存中
    // YLOGW("nvs reset");
    g_nvs.table[0].crc16 = y_utils_get_crc16((uint8_t *) &g_nvs, sizeof(NVS_st) / 2 - 2);  // 更新 crc16
    memcpy(&g_nvs.table[1], &g_nvs.table[0], sizeof(g_nvs.table[0]));
    y_ll_flash_erase(NVS_ADDR, sizeof(NVS_st));
    return y_ll_flash_write(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st)) ? true : false;  // 保存数据到内存中
}

/// @brief   初始化
/// @retval  true                          成功
/// @retval  false                         失败
bool y_nvs_init() {

    // 读取 3 次 防止失败
    for (int i = 0; i < 3; ++i) {

        // 读取 nvs 表 并检验 crc16
        y_ll_flash_read(NVS_ADDR, (uint8_t *) &g_nvs, sizeof(NVS_st));
        if (g_nvs.table[0].crc16 == y_utils_get_crc16((uint8_t *) &g_nvs.table[0], sizeof(NVS_st) / 2 - 2)) {
            return true;  // 主分区校验成功
        }
        if (g_nvs.table[1].crc16 == y_utils_get_crc16((uint8_t *) &g_nvs.table[1], sizeof(NVS_st) / 2 - 2)) {
            memcpy(&g_nvs.table[0], &g_nvs.table[1], sizeof(g_nvs.table[0]));  // 备用分区复制到主分区
            return true;                                                       // 备用分区校验成功
        }

        y_ll_delay(50);  // 延时一段时间
    }

    // 第一次上电 写入默认值
    y_nvs_reset();
    YLOGW("first set nvs");
    return false;
}
